package com.ai.wxy.spring.auth.conf;

import com.ai.wxy.spring.auth.rest.AuthenticationController;
import com.ai.wxy.spring.auth.security.DefaultConfigurerAdapter;
import com.ai.wxy.spring.auth.security.JwtAuthenticationEntryPoint;
import com.ai.wxy.spring.auth.security.JwtAuthorizationTokenFilter;
import com.ai.wxy.spring.auth.security.RoleBasedVoter;
import com.ai.wxy.spring.auth.service.IUrlRoleService;
import com.ai.wxy.spring.auth.service.IUserRoleService;
import com.ai.wxy.spring.auth.service.JwtUserDetailsService;
import com.ai.wxy.spring.auth.util.JwtTokenUtil;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.expression.WebExpressionVoter;

import java.util.Arrays;
import java.util.List;

/**
 * Spring Security Configuration
 *
 * @author 石头
 * @Date 2019/10/30
 * @Version 1.0
 **/
@Configuration
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class SecurityConfiguration{
    @Bean
    public JwtTokenUtil getJwtTokenUtil(){
        return new JwtTokenUtil();
    }

    @Bean
    public JwtAuthenticationEntryPoint getJwtAuthenticationEntryPoint(){
        return new JwtAuthenticationEntryPoint();
    }
    @Bean
    public AccessDeniedHandler accessDeniedHandler(){
        return new com.ai.wxy.spring.auth.security.AccessDeniedHandler();
    }
    @Bean
    public JwtAuthorizationTokenFilter getJwtAuthorizationTokenFilter(JwtTokenUtil jwtTokenUtil,JwtUserDetailsService userDetailsService){
        return new JwtAuthorizationTokenFilter(jwtTokenUtil,userDetailsService);
    }
    @Bean
    public AccessDecisionManager accessDecisionManager(){
        List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(new WebExpressionVoter(),new RoleBasedVoter(),new AuthenticatedVoter());
        return new UnanimousBased(decisionVoters);
    }
    @Bean
    @ConditionalOnBean(value = {IUrlRoleService.class})
    public DefaultConfigurerAdapter getDefaultConfigurerAdapter(AccessDeniedHandler accessDeniedHandler,AccessDecisionManager accessDecisionManager,JwtTokenUtil jwtTokenUtil,JwtAuthenticationEntryPoint unauthorizedHandler,JwtAuthorizationTokenFilter authenticationTokenFilter,IUrlRoleService urlRoleService){
        DefaultConfigurerAdapter defaultConfigurerAdapter = new DefaultConfigurerAdapter(jwtTokenUtil,unauthorizedHandler,authenticationTokenFilter,urlRoleService);
        defaultConfigurerAdapter.setAccessDecisionManager(accessDecisionManager);
        defaultConfigurerAdapter.setAccessDeniedHandler(accessDeniedHandler);

        return defaultConfigurerAdapter;
    }

    @Bean
    @ConditionalOnBean(value = {IUserRoleService.class})
    public JwtUserDetailsService getJwtUserDetailsService(IUserRoleService userRoleService){
        return new JwtUserDetailsService(userRoleService);
    }
    @Bean
    @ConditionalOnMissingBean(AuthenticationController.class)
    public AuthenticationController authenticationController(){
        return new AuthenticationController();
    }
}
